package reversi;
//Server.java
//Code from http://cs.lmu.edu/~ray/notes/javanetexamples/ was used to help build this file
//
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
/**
	Multithreaded server to handle multiple Reversi games
*/
public class Server{

    public static void main(String[] args) throws Exception {
        System.out.println("The Reversi server is running.");
        int clientNumber = 0;
        ServerSocket listener = new ServerSocket(9898);
        try {
            while (true) {
                new Game(listener.accept(), clientNumber++).start();
            }
        } finally {
            listener.close();
        }
    }

    /**
     * A private thread to handle a single Reversi game on a particular
     * socket.  The server terminates the connection when the game ends.
     */
    private static class Game extends Thread {
		private AI_Base myAI;
        private Socket socket;
		private int difficulty; //0 for Easy, 1 for Medium, 2 for Hard
		private boolean myMove;
        private int clientNumber;
		char myColor, theirColor;
		private Vector<Board> gameBoards;//Keep previous board states so we can undo moves
		private boolean display;
        public Game(Socket socket, int clientNumber) {
			myAI = new AI_Base();
            this.socket = socket;
            this.clientNumber = clientNumber;
            log("New connection with client# " + clientNumber + " at " + socket);
			gameBoards = new Vector<Board>();
			gameBoards.add(new Board());
			display = false;
			difficulty = 0;
        }

        /**
         * Services this thread's client by first sending the
         * client a welcome message, then getting the colors, then
		 * repeatedly reading moves and sending back moves.
         */
        public void run() {
            try {
                BufferedReader in = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));
                PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
				
				out.println("WELCOME;  Press enter to continue");
				in.readLine();
//				out.println("; Please select your color");
				while(true){//Get Color
					String input = in.readLine();
					if((input.toUpperCase()).startsWith("WHITE")){
						myColor = 'B';
						theirColor = 'W';
						myMove = true;
//						out.println("OK");
						break;
					}
					else if((input.toUpperCase()).startsWith("BLACK")){
						myColor = 'W';
						theirColor = 'B';
						myMove = false;
//						out.println("OK");
						break;
					}else{
						out.println("ILLEGAL; Please choose either black or white");
					}
				}
				while(true){//Get Difficulty
//					out.println(";Please select the AI difficulty.  Options are easy, medium, or hard.");
					String input = in.readLine();
					if((input.toUpperCase()).startsWith("HARD")){
						difficulty = 3;
						break;
					}else if((input.toUpperCase()).startsWith("MEDIUM")){
						difficulty = 2;
						break;
					}else if((input.toUpperCase()).startsWith("EASY")){
						difficulty = 1;
						break;
					}else{
//						out.println(";Invalid input.  :(");
					}
				}
				while(true){//
				if(myMove){
						int[] mv = myAI.Choose_Move(gameBoards.lastElement(), myColor, difficulty);
						gameBoards.add(new Board(gameBoards.lastElement()));
						if( mv[0]==-1){//Can't move
//							out.println("; Can't Move");
							out.println(gameBoards.lastElement().printBoard());
							myMove = false;
						}else{
						gameBoards.lastElement().performMove(mv[0], mv[1], myColor);
						myMove = false;
						String mvd = "";
						mvd+=(char)(mv[0]+97);
						mvd+=(char)(mv[1]+49);
//						out.println(mvd);
						if(display){
						out.println(gameBoards.lastElement().printBoard());
						}
					}
					}
					char winner = gameBoards.lastElement().whoWon();
					if(winner != 'N'){
//						out.println(gameBoards.lastElement().printBoard());
						out.println(";Game over. " + winner + " wins!");
						in.readLine();
						break;
					}
					String input = in.readLine();
					if((input.toUpperCase()).startsWith("DISPLAY")){
						display = !display;
//						out.println("OK");
						out.println(gameBoards.lastElement().printBoard());
					}else if((input.toUpperCase()).startsWith("EXIT")){
//						out.println("OK");
						break;
					}else if((input.toUpperCase()).startsWith("UNDO")){
						if(gameBoards.size()>2){
							out.println("OK");
							gameBoards.remove(gameBoards.size()-1);
							gameBoards.remove(gameBoards.size()-1);
							if(display){
								out.println(gameBoards.lastElement().printBoard());
							}
						}else{
							out.println("; Cannot undo any more moves!");
							out.println(gameBoards.lastElement().printBoard());
						}
					}else if((input.toUpperCase()).startsWith("EASY")){
						difficulty = 1;
//						out.println("OK");
					}else if((input.toUpperCase()).startsWith("MEDIUM")){
						difficulty = 2;
//						out.println("OK");
					}else if((input.toUpperCase()).startsWith("HARD")){
						difficulty = 3;
//						out.println("OK");
					}else{//Move
						if(input.length()>1){
							int x = input.charAt(0) - 97;//Columun
							int y = input.charAt(1)- 49;//Row
							if(gameBoards.lastElement().isLegal(x,y,theirColor)){
//								out.println("OK");
								gameBoards.add(new Board(gameBoards.lastElement()));//Put another copy of the current board state on the state list
								gameBoards.lastElement().performMove(x, y, theirColor);
								myMove = true;
//								if(display){
//								out.println(gameBoards.lastElement().printBoard());
//								}
							}else{
								if(gameBoards.lastElement().listLegalMoves(theirColor).size()==0){
//									out.println("OK; No legal moves for you! Passing.");
									out.println(gameBoards.lastElement().printBoard());
									myMove =true;
								}else{
//									out.println("ILLEGAL; Please enter a legal move!");
									out.println(gameBoards.lastElement().printBoard());
								}
							}
						}else{
//							out.println("ILLEGAL; Not a valid input!");
						}
					}

				}
			
            } catch (IOException e) {
                log("Error handling client# " + clientNumber + ": " + e);
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    log("Couldn't close a socket, what's going on?");
                }
                log("Connection with client# " + clientNumber + " closed");
            }
        }

        /**
         * Logs a simple message.  In this case we just write the
         * message to the server applications standard output.
         */
        private void log(String message) {
            System.out.println(message);
        }
    }
}